package com.wnxy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wnxy.dto.*;
import com.wnxy.exception.AddPerformException;
import com.wnxy.exception.DeleteException;
import com.wnxy.exception.QueryException;
import com.wnxy.exception.UpdateException;
import com.wnxy.model.Perform;
import com.wnxy.mapper.PerformMapper;
import com.wnxy.model.Room;
import com.wnxy.model.Seat;
import com.wnxy.model.Ticket;
import com.wnxy.service.PerformService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wnxy.service.RoomService;
import com.wnxy.service.SeatService;
import com.wnxy.service.TicketService;
import com.wnxy.util.BeanCopyUtil;
import com.wnxy.util.CommonsUtil;
import com.wnxy.util.DateUtil;
import com.wnxy.vo.QueryPageVo;
import com.wnxy.vo.UpPerformVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author alice
 * @since 2021-10-25
 */
@Service
@Transactional
public class PerformServiceImpl extends ServiceImpl<PerformMapper, Perform> implements PerformService {
    @Autowired
    private RoomService iRoomService;
    @Autowired
    private SeatService seatService;
    @Autowired
    private TicketService ticketService;
    @Autowired
    private RedisTemplate<String, Object> rt;
    @Autowired
    private StringRedisTemplate srt;

    @Override
    public PerformDto savePerform(Perform perform) throws ParseException {
        if(null==perform) throw new AddPerformException(StatusCode.ADDERROR.getCode(),"添加失败");

        Long performtime = DateUtil.parseDateString(perform.getPerformTime(), "yyyy-MM-dd HH:mm:ss");
        if (performtime<System.currentTimeMillis()) throw new AddPerformException(StatusCode.ADDERROR.getCode(), "时间不符合要求,添加失败");
        Room room = iRoomService.getOne(new QueryWrapper<Room>().eq("room_id", perform.getPerformRoomId()));
        if(null==room) throw new AddPerformException(StatusCode.ADDERROR.getCode(), "演出厅不存在,添加失败");
        if (room.getRoomStatus()!=0) throw new AddPerformException(StatusCode.ADDERROR.getCode(), "演出厅不可使用,添加失败");
        perform.setPerformRoomName(room.getRoomName());
        String now = DateUtil.parseDateLong(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
        perform.setPerformAddTime(now);
        boolean save = saveOrUpdate(perform);
        if(!save) throw new AddPerformException(StatusCode.ADDERROR.getCode(), "添加失败");
        PerformDto performDto = BeanCopyUtil.copyProperties(perform, PerformDto.class);
        return performDto;
    }
    @Override
    public PageDto pageQuery(QueryPageVo pageVo) {
        QueryWrapper<Perform> qw = new QueryWrapper<>();
        if(null!=pageVo.getPerformRoomId()) qw.eq("perform_room_id",pageVo.getPerformRoomId());
        if(null!=pageVo.getPerformCategory()) qw.eq("perform_category",pageVo.getPerformCategory());
        if(null!=pageVo.getStartTime()) qw.ge("perform_time",pageVo.getStartTime());
        if(null!=pageVo.getEndTime()) qw.le("perform_time",pageVo.getEndTime());
        if(null!=pageVo.getPerformStatus()) qw.eq("perform_status",pageVo.getPerformStatus());
        String keyword = pageVo.getKeyword();
        if(null!=keyword&&!keyword.trim().equals("")) {
            qw.and(qwt -> {
                qwt.like("perform_title", keyword).or()
                        .like("perform_desc", keyword).or()
                        .like("perform_category_name", keyword).or()
                        .like("perform_room_name", keyword);
            });
        }
//        qw.ne("perform_status",3);
        qw.orderByDesc("perform_id");
        Page<Perform> page = page(new Page<>(pageVo.getCurrent(), pageVo.getSize()),qw);
        PageDto pageDto = BeanCopyUtil.copyProperties(page, PageDto.class);
        pageDto.setRecords(BeanCopyUtil.copyList(page.getRecords(),PerformDto.class));
        return pageDto;
    }
    @Override
    public DeleteDto delPerformByIds(List<Integer> ids) {
        List<Perform> performs = listByIds(ids);
        ArrayList<Integer> list = new ArrayList<>();
        performs.forEach(perform->{
        list.add(perform.getPerformId());//数组保存可以进行删除的id
            perform.setPerformStatus(0);
            //删除redis对应表演id的票务数据
            System.out.println(perform);
            rt.delete("wnxy:theater:ticket:"+perform.getPerformId());
        });
        ids.removeAll(list);//不能删除的ids
        //.下架删除对应ticket
//        boolean remove = ticketService.remove(new QueryWrapper<Ticket>().in("ticket_perform_id", list));
        boolean b = updateBatchById(performs);
        if(!b) throw new DeleteException(StatusCode.DELETEERROR.getCode(), "删除失败");
//        if(!remove) throw new DeleteException(StatusCode.DELETEERROR.getCode(), "删除失败");
        DeleteDto deleteDto = new DeleteDto();
        deleteDto.setDelIds(list);
        deleteDto.setNotDelIds(ids);
        return deleteDto;
    }
    @Override
    public DeleteDto upPerformByIds(Integer id) {
        Perform one = getOne(new QueryWrapper<Perform>().eq("perform_id", id));
        return null;
    }
    @Transactional(rollbackFor = Exception.class)
    //发布演出信息
    @Override
    public TicketsDto upPerform(UpPerformVo upPerformVo) throws ParseException, IllegalAccessException {
        //判断信息是否完整
        if (!CommonsUtil.hasAllFields(upPerformVo)) throw new UpdateException(StatusCode.UPERROR.getCode(), "请填写完整信息");
    //先判断时间是否符合
        Long start = DateUtil.parseDateString(upPerformVo.getPerformTime(), "yyyy-MM-dd HH:mm:ss");
        Long end = DateUtil.parseDateString(upPerformVo.getPerformEndtime(), "yyyy-MM-dd HH:mm:ss");
        Long now = System.currentTimeMillis();
        if(end<start||(end-start)>60*60*1000*3||start<now+60*60*1000*24*7) throw new UpdateException(StatusCode.UPERROR.getCode(), "时间不符合标准");

            //演出时间必须提前一周,开始结束时间应正确
        Perform perform = getOne(new QueryWrapper<Perform>().eq("perform_id", upPerformVo.getPerformId()));
        if(null==perform) throw new UpdateException(StatusCode.UPERROR.getCode(), "演出信息不存在");
        if(perform.getPerformStatus()==1) throw new UpdateException(StatusCode.UPERROR.getCode(), "演出信息已发布,不能重复发布");
        if (upPerformVo.getPerformSeatIds().size()<10) throw new UpdateException(StatusCode.UPERROR.getCode(), "至少10人一场");
        //1.根据影厅和时间判断是否有冲突
            QueryWrapper<Perform> qw = new QueryWrapper<>();
            qw.eq("perform_status",1)//查寻已发布信息
            .eq("perform_room_id",upPerformVo.getPerformRoomId())//根据影厅查找
            .ge("perform_time",upPerformVo.getPerformTime())
            .le("perform_time",upPerformVo.getPerformEndtime());//查询时间段内记录
            Perform one = getOne(qw);
            if(one!=null) throw new UpdateException(StatusCode.UPERROR.getCode(), "发布失败,该场次已被占用");
            // 2.更改演出信息状态
//            Room roomById = iRoomService.getById(upPerformVo.getPerformRoomId());
        Room room = iRoomService.getOne(new QueryWrapper<Room>().eq("room_id", upPerformVo.getPerformRoomId()));
            perform.setPerformRoomId(upPerformVo.getPerformRoomId());//发布影厅
            perform.setPerformRoomName(room.getRoomName());
            perform.setPerformStatus(1);
            perform.setPerformTime(upPerformVo.getPerformTime());
            perform.setPerformEndtime(upPerformVo.getPerformEndtime());
        boolean b = updateById(perform);
        if(!b) throw new UpdateException(StatusCode.UPERROR.getCode(),"更改信息失败");
        //3.判断座位是否可用
        List<Seat> seats = seatService.list(new QueryWrapper<Seat>()
                .eq("seat_room_id", upPerformVo.getPerformRoomId())
        .eq("seat_status",0).in("seat_id",upPerformVo.getPerformSeatIds()));//该影厅可用座位
        //4.添加票务
        ArrayList<Ticket> tickets = new ArrayList<>();
//        if(seats.size()<0) throw new UpdateException(StatusCode.UPERROR.getCode(), "座位")
        if (seats.size()<10) throw new UpdateException(StatusCode.UPERROR.getCode(), "可用座位不足10人一场");
        //使用redis储存票务数据
//        Map<Object, Object> entries = rt.opsForHash().entries("wnxy:theater:ticked");
//        int ticketid = entries.size()+1;
        int ticketid = 1;
        for (Seat seat : seats) {
            Ticket ticket = new Ticket();
            ticket.setTicketId(ticketid);
            ticket.setTicketPerformId(perform.getPerformId());
            ticket.setTicketPerformTitle(perform.getPerformTitle());
            ticket.setTicketRoomId(perform.getPerformRoomId());
            ticket.setTicketRoomName(perform.getPerformRoomName());
            ticket.setTicketPrice(upPerformVo.getTicketPrice());
            ticket.setTicketSeatId(seat.getSeatId());
            ticket.setTicketStatus(0);
            tickets.add(ticket);
//            ticketService.save(ticket);
            rt.opsForHash().put("wnxy:theater:ticket:"+perform.getPerformId(),ticketid+"",ticket);
            ticketid++;
        }
        Long expireTime = DateUtil.parseDateString(perform.getPerformEndtime(), "yyyy-MM-dd HH:mm:ss") - System.currentTimeMillis();
        System.out.println(expireTime);
        rt.opsForHash().getOperations().expire("wnxy:theater:ticket:"+perform.getPerformId(),expireTime, TimeUnit.MILLISECONDS);
//        seats.forEach(seat -> {//生成座位对应的票
//        });
        //存入redis数据库
//        rt.opsForHash().put("wnxy:theater:ticket",perform.getPerformId()+"",tickets);
        System.out.println(tickets);
        TicketsDto ticketsDto = new TicketsDto();
        ticketsDto.setTickets(tickets);
//        ticketService.saveBatch(tickets);
        return ticketsDto;
    }

    @Override
    public List<PlanDto> loadPlan(Integer performRoomId) {
        List<Perform> list = list(new QueryWrapper<Perform>().eq("perform_room_id", performRoomId).eq("perform_status", 1).orderByAsc("perform_time"));
        if(list==null) throw new QueryException(StatusCode.ERROR.getCode(), "信息不存在");
        ArrayList<PlanDto> planDtos = new ArrayList<>();
        for (Perform perform : list) {
            System.out.println(perform);
            List<Object> ticketsObj = rt.opsForHash().values("wnxy:theater:ticket:" + perform.getPerformId());
//            List<Ticket> tickets = new ArrayList<Ticket>(values);
            List<Ticket> tickets = BeanCopyUtil.copyList(ticketsObj, Ticket.class);
//            List<Ticket> tickets = ticketService.list(new QueryWrapper<Ticket>().eq("ticket_room_id", performRoomId).eq("ticket_perform_id",perform.getPerformId()));
            if(tickets==null||tickets.size()==0) throw new QueryException(StatusCode.ERROR.getCode(), "票务信息不存在");
            PlanDto planDto = new PlanDto();
            planDto.setPerform(perform);
            planDto.setTiketPrice(tickets.get(0).getTicketPrice());
            planDto.setTiketCounts(tickets.size());
            planDtos.add(planDto);
        }
        return planDtos;
    }
}
